﻿/*************************************************************************************
 * 工    具：  HK_TodoList
 * 
 * 描    述：  Unity工程内的TodoList管理
 * 
 * 版    本：  V1.0
 * 作    者：  京产肠饭、王凯
 * 
 * 创    建：  2024/05/14  V1.0
 * 
 * 链    接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using UnityEditorInternal;
using System.Linq;
using System;

namespace HKTools
{
    // 自定义关键字配置
    public static class HK_TodoList
    {
        public static List<string> skipKeyWords = new List<string> { "HK_TodoList", "QFramework", "Plugins" };

        static string dataPath = "Assets/HKTools/ForEditor/2.1HK_TodoList/Scripts/Editor/HK_TodoListData.asset";
        static List<string> todoKeyWords = new List<string> { "//TODO", "//Todo", "//todo", "// TODO", "// Todo", "// todo" };

        static HK_TodoListData todoListData;
        public static HK_TodoListData TodoListData
        {
            get
            {
                if (todoListData == null)
                {
                    todoListData = AssetDatabase.LoadAssetAtPath<HK_TodoListData>(dataPath);
                }

                if (todoListData == null)
                {
                    todoListData = ScriptableObject.CreateInstance<HK_TodoListData>();
                    AssetDatabase.CreateAsset(todoListData, dataPath);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                }

                return todoListData;
            }
        }

        /// <summary>
        /// 清空现有的TODO列表
        /// </summary>
        public static void RefreshTodoListData()
        {
            if (TodoListData.TodoList == null)
                TodoListData.TodoList = new List<string>();
            else
                TodoListData.TodoList.Clear();

            if (TodoListData.CommentedList == null)
                TodoListData.CommentedList = new List<string>();
            else
                TodoListData.CommentedList.Clear();
        }

        /// <summary>
        /// 读取对应路径的脚本文件，并将 Todo相关的行存储到 TodoListData 中
        /// </summary>
        /// <param name="assetPath"></param>
        public static void SaveTodoListData(string assetPath)
        {
            string[] lines = File.ReadAllLines(assetPath);

            for (int i = 0; i < lines.Length; i++)
            {
                bool isTodoLine = todoKeyWords.Any(keyword => lines[i].Contains(keyword, StringComparison.OrdinalIgnoreCase));

                if (!isTodoLine)
                    continue;

                string todoItem = string.Format("{0} 第 {1} 行", assetPath, i + 1);

                if (!TodoListData.TodoList.Contains(todoItem))
                {
                    TodoListData.TodoList.Add(todoItem);
                    TodoListData.CommentedList.Add(lines[i].Trim());
                }
            }
        }
    }

    public class HK_TodoListWindow : EditorWindow
    {
        ReorderableList reorderableList;
        Vector2 scrollPosition;

        [MenuItem("HKTools/Todo List (待办事项清单工具)", priority = HK_MenuPriority.HK_TodoListTool)]
        static void Init()
        {
            HK_TodoListWindow todoWindow = GetWindow<HK_TodoListWindow>("TodoList（待办事项清单）");
            todoWindow.Show();
        }

        void OnEnable()
        {
            if (HK_TodoList.TodoListData == null)
                return;

            // 打开窗口的时候，重新刷新一次
            GlobalRefresh();

            reorderableList = new ReorderableList(HK_TodoList.TodoListData.TodoList, typeof(string), false, false, false, false);
            reorderableList.elementHeightCallback = index => EditorGUIUtility.singleLineHeight * 2.5f;

            // 绘制列表每一项的回调
            reorderableList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
            {
                string todoItem = HK_TodoList.TodoListData.TodoList[index];
                string commentedItem = HK_TodoList.TodoListData.CommentedList[index];

                EditorGUI.LabelField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), (index + 1).ToString() + ".");
                EditorGUI.LabelField(new Rect(rect.x + 15, rect.y, rect.width, EditorGUIUtility.singleLineHeight), todoItem);

                // 创建绿色文本样式
                GUIStyle greenTextStyle = new GUIStyle();
                greenTextStyle.normal.textColor = new Color(0.1f, 0.7f, 0);

                EditorGUI.LabelField(new Rect(rect.x + 15, rect.y + 22, rect.width, EditorGUIUtility.singleLineHeight), commentedItem, greenTextStyle);

                if (GUI.Button(new Rect(rect.width - 75, rect.y + 12, 80, EditorGUIUtility.singleLineHeight * 1.2f), "打开脚本"))
                {
                    OpenScriptFile(todoItem);
                }

                if (index > 0)
                {
                    // 绘制分割线
                    Handles.color = Color.gray;
                    Handles.DrawLine(new Vector2(rect.x, rect.y - 1), new Vector2(rect.x + rect.width, rect.y - 1));
                }
            };
        }

        void OnGUI()
        {
            GUILayout.Space(10);
            // 使用水平布局
            GUILayout.BeginHorizontal();
            // 添加弹性空间
            GUILayout.FlexibleSpace();

            if (GUILayout.Button("全局刷新", GUILayout.Width(150)))
            {
                GlobalRefresh();
            }

            // 结束水平布局
            GUILayout.EndHorizontal();
            GUILayout.Space(10);
            // 使用垂直布局
            GUILayout.BeginVertical();

            // 创建滚动视图
            scrollPosition = GUILayout.BeginScrollView(scrollPosition);
            reorderableList.DoLayoutList(); // 绘制列表

            // 结束滚动视图
            GUILayout.EndScrollView();
            // 结束垂直布局
            GUILayout.EndVertical();
        }

        void OpenScriptFile(string path)
        {
            if (string.IsNullOrEmpty(path))
                return;

            string[] pathArray = path.Split(' ');

            string assetPath = pathArray[0];
            int line = int.Parse(pathArray[pathArray.Length - 2]);

            // 加载脚本资源
            UnityEngine.Object asset = AssetDatabase.LoadAssetAtPath(assetPath, typeof(UnityEngine.Object));

            if (asset != null)
            {
                // 打开脚本资源
                AssetDatabase.OpenAsset(asset, line);
            }
            else
            {
                Debug.LogError("当前脚本路径错误: " + assetPath);
            }
        }

        void GlobalRefresh()
        {
            string[] allFilePath = Directory.GetFiles(Application.dataPath, "*.cs", SearchOption.AllDirectories).Select(fullPath => "Assets" + fullPath.Substring(Application.dataPath.Length).Replace('\\', '/')).ToArray();

            // 清空现有的TODO列表
            HK_TodoList.RefreshTodoListData();

            foreach (string filePath in allFilePath)
            {
                bool isSkip = HK_TodoList.skipKeyWords.Any(keyword => filePath.Contains(keyword, StringComparison.OrdinalIgnoreCase));

                if (isSkip)
                    continue;

                HK_TodoList.SaveTodoListData(filePath);
            }

            EditorUtility.SetDirty(HK_TodoList.TodoListData);
        }
    }

    public class HK_TodoListPostprocessor : AssetPostprocessor
    {
        static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
        {
            if (HK_TodoList.TodoListData == null)
                return;

            foreach (string assetPath in importedAssets)
            {
                // 是否是需要跳过的路径
                bool isSkip = HK_TodoList.skipKeyWords.Any(keyword => assetPath.Contains(keyword, StringComparison.OrdinalIgnoreCase));

                // 如果该文件是 不是 .cs 文件，且是过滤的文件路径
                if (isSkip || !assetPath.EndsWith(".cs"))
                    continue;

                // 判断 todoList 中，是否包含该脚本
                List<string> removeList = HK_TodoList.TodoListData.TodoList.Where(item => item.Contains(assetPath)).ToList();

                if (removeList.Count > 0)
                {
                    foreach (var item in removeList)
                    {
                        int index = HK_TodoList.TodoListData.TodoList.IndexOf(item);
                        HK_TodoList.TodoListData.CommentedList.RemoveAt(index);
                        HK_TodoList.TodoListData.TodoList.Remove(item);
                    }
                }

                HK_TodoList.SaveTodoListData(assetPath);
                EditorUtility.SetDirty(HK_TodoList.TodoListData);
            }
        }
    }
}